/****************************************************************
 * I am the AC 130 vs Pirate game. I allow the user to control an 
 * AC130 gunship in the hunt for Modern day pirates. The player  
 * will be allowed to roam free across a section of ocean/coastline.  
 * In the water there will be four types of vessels: Merchant  
 * ships that the player must protect, Pirate ships that the player  
 * must identify and destroy, Fishing boats that look like Pirate  
 * ships that the player must not destroy, and Friendly Navy ships  
 * that can capture pirates for extra points. Time permitting there  
 * may also be ground targets to attack. 
 *
 * Key elements of this project will be the Player/AC130, the Ships,  
 * the ShipAI system, the collision grid, the debris controller, the  
 * Ground/Water, Clouds, and scoring system. This project will make  
 * use of an external text file to store useful game parameters,  
 * thus allowing us to play balance the game without recompiling  
 * the executable. 
 *****************************************************************
 * I am the Ground class. I contain all the information to render
 *****************************************************************/
#include "ground.h"



/// Load starting maps
Ground::Ground(){
	map = create_bitmap(64,64);
		/// populate tile grid with nulls
	for(int itor = 0; itor < MAXTILE ; itor++){
		tile[itor] = NULL;
	}
	isEdit = true;
}
Ground::~Ground(){
	destroy_bitmap(map);
}

/// take in the Game Data and 
void Ground::Init(GameData * data, CrashBin * exCrashBin){
	gd = data;
	myCrashBin = exCrashBin;
		// map data
	tileW = gd->GetNum("tileWidth");
	tileH = gd->GetNum("tileHeight");
		// ensure valid map data
	if(tileW < 1) tileW = 64;
	if(tileH < 1) tileH = 64;
			// draw data
	waterR = gd->GetNum("waterRed"); 
	waterG = gd->GetNum("waterGreen");
	waterB = gd->GetNum("waterBlue");

	tileMax = gd->GetNum("tileMax");
	if(tileMax > MAXTILE) tileMax = MAXTILE;
		// create blank first tile
	tile[0] = create_bitmap(tileW,tileH);
	clear_to_color(tile[0], makecol(255,0,255));
		// load as many tiles as we have room for
	for(int itor = 1; itor < tileMax ; itor++){
		char * path = gd->GetStr("tileTex",itor);
		tile[itor] = load_bitmap(path, NULL);
			// exit on failed load assume no more tiles
		if(tile[itor] == NULL) {
			tileMax=itor;
			sprintf(gd->debugTxt, "tile Load failed on: %d , %s",itor, path);
		}
	}
		// create border tile
	border = create_bitmap(tileW,tileH);
	clear_to_color(border, makecol(255,0,0));
	rectfill(border,2,2,border->w,  border->h,makecol(255,0,255));

	// load edit Map as a starter
	LoadMap(gd->GetStr("mapEdit"));
}

/// I am the world to map conversion functions. I convert World
/// coordinats to map coordinates I exicute bounds checks in 
/// addition to conversion math.
int Ground::GetMapX(int worldX){
	int ret =  worldX/tileW;
	if(ret < 0) ret = 0;
	if(ret > map->w-1)ret = map->w-1;
	return ret;
}
/// same as X
int Ground::GetMapY(int worldY){
	int ret =  worldY/tileH;
	if(ret < 0) ret = 0;
	if(ret > map->h-1)ret = map->h-1;
	return ret;
}
/// I am the tile index retrival funcion I check the map file and
/// return the index of the tile we are looking at
int Ground::GetTile(int mapX, int mapY){
	int pix = getpixel(map,mapX,mapY);
	int ret = (getr(pix) + getg(pix) );	// 256 possible pixel values
	if(ret < 0) ret =0;
	if(ret > tileMax-1)ret = tileMax-1;
	return ret;
}

/// I am the edit function tile picker I match the overlay
/// and return the index of the tile that the mouse is over
int Ground::PickTile(int screenX, int screenY){
		// pull render settings from file
	int step = gd->GetNum("tilePickDim" );
	int width = gd->GetNum("tilePickWid" );
	if(width <1) width = 1;	// 
	int xval, yval;
	for(int itor = 0; itor < tileMax; itor++){
		// compute x/yval for this itor
		xval = (itor%width)*step;
		yval = (itor/width)*step;
			// check if this is the tile we are in
		if( screenX >= xval && screenY >= yval &&
			screenX < xval+step && screenY < yval+step )
		{
			return itor;	// return index
		}
	}
		// default to 0 tile
	return 0;
}

/// I am the map modification function. I alter a single
/// pixel of the map to the tile index
void Ground::SetTile(int mapX, int mapY, int tileInd){
	// bounds check input data
	if(tileInd > tileMax) tileInd = tileMax;
	if(mapX < 0) mapX = 0;
	if(mapY < 0) mapY = 0;
	if(mapX > map->w-1) mapX = map->w-1;
	if(mapY > map->h-1) mapY = map->h-1;
		// set color values
	int r = tileInd;
	int g = tileInd-256;
	int b = 250;
		// modify color values
	if( r > 255) r = 255;
	if( g < 0) g = 0;
		// toggle blue to give better definition in the raw data
		// tiles before tileWaterSplit are blue for water
	if( tileInd >= gd->GetNum("tileWaterSplit")) b = 0;
		// set the pixel
	putpixel(map, mapX, mapY, makecol(r,g,b));
}

/// We are the file functions we save/load the current map BITMAP
/// to/from a file to impliment level editing and multi level loading
void Ground::LoadMap(char * fname){
		// compute path
	char tmp[128];
	strncpy(tmp,fname,128);	// copy path before it gets clobbered
	char path[256];
	strncpy(path,gd->GetStr("mapPath"), 200);
	strncat(path, tmp, 50);
	strncat(path,".bmp",5);
	// delete old map
	destroy_bitmap(map);
	map = load_bitmap(path,NULL);
		// ensure map is valid
	if(map == NULL) map = create_bitmap(64,64);
		// set crash grid to new map size
	myCrashBin->SetLevel(map->w*tileW, map->h*tileH);
	// todo make minimap
}
void Ground::SaveMap(char * fname){
	char tmp[128];
	strncpy(tmp,fname,128);	// copy path before it gets clobbered
		// compute path
	char path[256];
	strncpy(path,gd->GetStr("mapPath"), 200);
	strncat(path, tmp, 50);
	strncat(path,".bmp",5);
		// output bitmap
	save_bitmap(path,map,NULL);

}


/// I am the base water rendering function. I draw the water 
/// that needs to be rendered before the dirt
void Ground::DrawWater( Camera * cam){
		//clear screen to water color
	clear_to_color(cam->worldSc, makecol(waterR, waterG, waterB));
		// todo draw caustic animation
}

/// I am the dirt rendering function I draw the tiles that comprise
/// the ground as viewed by the camera
void Ground::DrawGround( Camera * cam){
		// compute starting and ending locations by taking advantage of
		// floating point percision loss for divide then multiply 
		// operations.
	int startX = ((int)(cam->center->x - cam->worldSc->w/2)/tileW)*tileW;
	int endX = ((int)(cam->center->x + cam->worldSc->w/2)/tileW)*tileW;
	int startY = ((int)(cam->center->y - cam->worldSc->h/2)/tileH)*tileH;
	int endY = ((int)(cam->center->y + cam->worldSc->h/2)/tileH)*tileH;
		// shift start andend the extra bit
	endX += tileW;
	endY += tileH;
	startX -= tileW;
	startY -= tileH;
		// iterate between start and end points incrimenting by
		// tileW  and tileH
	for(int itorX = startX; itorX < endX; itorX += tileW){
		for(int itorY = startY; itorY < endY; itorY += tileH){
				// fetch tile at map coordinates
			int index = GetTile(GetMapX(itorX+4),GetMapX(itorY+4));
				// draw tile onto worldSc at propper location
			cam->WorldDrawSprite(tile[index],itorX, itorY);
			
				// draw guide lines
			if(isEdit){
				cam->WorldDrawSprite( border,itorX, itorY);
			}
		}
	}
}

/// I am the tile pick renderer. I draw all the tile types to the 
/// screen and highlight the curTile that the user has sellected.
/// this in conjunction with PickTile will make map editing easier
void Ground::DrawTilePick( Camera * cam, int curTile){
	// draw tile list to screen, no zoom
	clear_to_color(cam->screen, makecol(0,0,0));

	int step = gd->GetNum("tilePickDim" );
	int width = gd->GetNum("tilePickWid" );
	if(width <1) width = 1;	// 
	int xval, yval;
	for(int itor = 0; itor < tileMax; itor++){
		// compute x/yval for this itor
		xval = (itor%width)*step;
		yval = (itor/width)*step;
			// draw sprite
		stretch_sprite(cam->screen, tile[itor], xval+1,yval+1,step-1,step-1);
			// check if this is the chosen tile and highlight it
		if( curTile == itor )
		{
			rect(cam->screen,xval,yval,xval+step,yval+step, 
				makecol(255,0,0));	// return index
		}
	}
}